package com.lty.jeeg.server.common.utils;

import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lty.jeeg.server.common.dto.GenerateInput;

/**
 * @author LTY
 */
public class TemplateUtil {

	private static final Logger log = LoggerFactory.getLogger("adminLogger");

	private static String getTemplate(String fileName) {
		return getTemplate(fileName, 0);
	}

	private static String getTemplate(String fileName, Integer category) {
		String path = category == 0 ? "generate/normal/" : "generate/tree/";
		return FileUtil.getText(
				TemplateUtil.class.getClassLoader().getResourceAsStream(path + fileName)
		);
	}

	/**
	 * 生成java model
	 * @param input 生成模板
	 */
	public static void saveJava(GenerateInput input) {
		// 保存路径
		String path = input.getPath();
		// 包名
		String beanPackageName = input.getBeanPackageName();
		// 类名
		String beanName = input.getBeanName();
		// 字段名List
		List<String> beanFieldName = input.getBeanFieldName();
		// 字段类型List
		List<String> beanFieldType = input.getBeanFieldType();
		// 字段数据库默认值List
		List<String> beanFieldValue = input.getBeanFieldValue();
		// 字段注释List
		List<String> beanFieldComment = input.getBeanFieldComment();

		/*
			替换模板
		 */
		String text = getTemplate("java.txt", input.getCategory());
		text = text.replace("{beanPackageName}", beanPackageName)
				.replace("{beanName}", beanName);

		// 引入包名
		String imports = "";
		if (beanFieldType.contains(BigDecimal.class.getSimpleName())) {
			imports += "import " + BigDecimal.class.getName() + ";\n";
		}
		if (beanFieldType.contains(Date.class.getSimpleName())) {
			imports += "import " + Date.class.getName() + ";";
		}

		text = text.replace("{import}", imports);

		// 获取所有字段
		String fields = getFields(beanFieldName, beanFieldType, beanFieldValue, beanFieldComment);
		text = text.replace("{fields}", fields);
		// getter&setter已经被lombok取代
		text = text.replace("{getset}", getset(beanFieldName, beanFieldType));

		text = text.replace("{date}", DateUtils.getDateTime());

		text = text.replace("{tableComment}", input.getTableComment());

		// 生成文件
		FileUtil.saveTextFile(text,
				path + File.separator + getPackagePath(beanPackageName) + beanName + ".java");
		log.debug("生成java model：{}模板", beanName);
	}

	/**
	 * 获取所有字段拼接的字符串
	 * @param beanFieldName 字段名
	 * @param beanFieldType 字段类型
	 * @param beanFieldValue 字段数据库默认值
	 * @param beanFieldComment 字段注释
	 * @return 替换用的字符串
	 */
	private static String getFields(List<String> beanFieldName, List<String> beanFieldType,
									List<String> beanFieldValue, List<String> beanFieldComment) {
		StringBuilder builder = new StringBuilder();
		int size = beanFieldName.size();
		for (int i = 0; i < size; i++) {
			String name = beanFieldName.get(i);
			// 跳过通用字段
			if ("id".equals(name)
					|| "createTime".equals(name)
					|| "updateTime".equals(name)
					|| "remark".equals(name)
					|| "createBy".equals(name)
					|| "updateBy".equals(name)
					|| "isDeleted".equals(name)) {
				continue;
			}
			String type = beanFieldType.get(i);
			String comment = beanFieldComment.get(i);
			builder.append("\t/** \n\t ")
					.append(comment)
					.append("\n\t  */\n\t")
					.append("private ")
					.append(type)
					.append(" ")
					.append(name)
					.append(";\n\n");
		}

		return builder.toString();
	}

	/**
	 * 获取getter&setter
	 * 已经被lombok取代
	 * @param beanFieldName 字段名
	 * @param beanFieldType 字段类型
	 * @return 替换用的字符串
	 */
	private static String getset(List<String> beanFieldName, List<String> beanFieldType) {
		StringBuilder builder = new StringBuilder();
		int size = beanFieldName.size();
		for (int i = 0; i < size; i++) {
			String name = beanFieldName.get(i);
			if ("id".equals(name) || "createTime".equals(name) || "updateTime".equals(name)) {
				continue;
			}

			String type = beanFieldType.get(i);
			builder.append("\tpublic ")
					.append(type)
					.append(" get")
					.append(StringUtils.substring(name, 0, 1).toUpperCase())
					.append(name, 1, name.length())
					.append("() {\n")
					.append("\t\treturn ").append(name).append(";\n")
					.append("\t}\n")
					.append("\tpublic void set")
					.append(StringUtils.substring(name, 0, 1).toUpperCase())
					.append(name, 1, name.length())
					.append("(")
					.append(type)
					.append(" ")
					.append(name)
					.append(") {\n")
					.append("\t\tthis.").append(name).append(" = ").append(name).append(";\n")
					.append("\t}\n");
		}

		return builder.toString();
	}

	/**
	 * 生成持久层文件（dao&mapper.xml）
	 * @param input 生成模板
	 */
	public static void saveJavaDao(GenerateInput input) {
		// 保存路径
		String path = input.getPath();
		// 表名
		String tableName = input.getTableName();
		// 包名
		String beanPackageName = input.getBeanPackageName();
		// 类名
		String beanName = input.getBeanName();
		// dao包名
		String daoPackageName = input.getDaoPackageName();
		// dao名
		String daoName = input.getDaoName();

		/*
			生成dao
		 */
		String text = getTemplate("dao.txt", input.getCategory());
		text = text.replace("{date}", DateUtils.getDateTime());
		text = text.replace("{tableComment}", input.getTableComment());
		text = text.replace("{daoPackageName}", daoPackageName);
		text = text.replace("{beanPackageName}", beanPackageName);
		text = text.replace("{daoName}", daoName);
		text = text.replace("{table_name}", tableName);
		text = text.replace("{beanName}", beanName);
		text = text.replace("{beanParamName}", lowerFirstChar(beanName));

		// 替换dao中insert语句
		String insertColumns = getInsertColumns(input.getColumnNames());
		text = text.replace("{insert_columns}", insertColumns);
		String insertValues = getInsertValues(input.getColumnNames(), input.getBeanFieldName());
		text = text.replace("{insert_values}", insertValues);
		FileUtil.saveTextFile(text,
				path + File.separator + getPackagePath(daoPackageName) + daoName + ".java");
		log.debug("生成java dao：{}模板", beanName);

		text = getTemplate("mapper.xml", input.getCategory());
		text = text.replace("{beanPackageName}", beanPackageName);
		text = text.replace("{daoPackageName}", daoPackageName);
		text = text.replace("{daoName}", daoName);
		text = text.replace("{table_name}", tableName);
		text = text.replace("{beanName}", beanName);
		String sets = getUpdateSets(input.getColumnNames(), input.getBeanFieldName());
		text = text.replace("{update_sets}", sets);
		String where = getWhere(input.getColumnNames(), input.getBeanFieldName());
		text = text.replace("{where}", where);
		FileUtil.saveTextFile(text,
				path + File.separator + "mybatis-mappers" + File.separator + beanName + "Mapper.xml");
		log.debug("生成mapper：{}模板", beanName);
	}

	/**
	 * 获得insert语句中字段值拼接的字符串
	 * @param columnNames 列名List
	 * @param beanFieldName 字段名List
	 * @return 替换用的字符串
	 */
	private static String getInsertValues(List<String> columnNames, List<String> beanFieldName) {
		StringBuilder builder = new StringBuilder();
		int size = columnNames.size();
		for (int i = 0; i < size; i++) {
			String column = columnNames.get(i);
			if (!"id".equals(column)) {
				builder.append("#{")
						.append(beanFieldName.get(i))
						.append("}, ");
			}
		}

		return StringUtils.substringBeforeLast(builder.toString(), ",");
	}

	/**
	 * 获得insert语句中字段名拼接的字符串
	 * @param columnNames 字段名List
	 * @return 替换用的字符串
	 */
	private static String getInsertColumns(List<String> columnNames) {
		StringBuilder builder = new StringBuilder();
		for (String column : columnNames) {
			if (!"id".equals(column)) {
				builder.append(column).append(", ");
			}
		}

		return StringUtils.substringBeforeLast(builder.toString(), ",");
	}

	private static String getUpdateSets(List<String> columnNames, List<String> beanFieldName) {
		StringBuilder builder = new StringBuilder();
		int size = columnNames.size();
		for (int i = 0; i < size; i++) {
			String columnName = columnNames.get(i);
			String beanFiledName = beanFieldName.get(i);
			if (!"id".equals(columnName)
					&& !"createBy".equals(columnName)
					&& !"createTime".equals(columnName)
					&& !"updateTime".equals(columnName)) {
				builder.append("\t\t\t<if test=\"")
						.append(beanFiledName)
						.append(" != null\">\n")
						.append("\t\t\t\t")
						.append(columnName)
						.append(" = ")
						.append("#{")
						.append(beanFiledName)
						.append("}, \n")
						.append("\t\t\t</if>\n");
			}
		}

		return builder.toString();
	}

	private static String getWhere(List<String> columnNames, List<String> beanFieldName) {
		StringBuilder builder = new StringBuilder();
		int size = columnNames.size();
		for (int i = 0; i < size; i++) {
			String column = columnNames.get(i);
			builder.append("\t\t\t<if test=\"params.")
					.append(column)
					.append(" != null and params.")
					.append(column)
					.append(" != ''\">\n")
					.append("\t\t\t\tand ")
					.append(column)
					.append(" = ")
					.append("#{params.")
					.append(beanFieldName.get(i))
					.append("} \n")
					.append("\t\t\t</if>\n");
		}

		return builder.toString();
	}

	/**
	 * 变量名
	 *
	 * @param beanName beanName
	 * @return name
	 */
	public static String lowerFirstChar(String beanName) {
		String name = StrUtil.str2hump(beanName);
		String firstChar = name.substring(0, 1);
		name = name.replaceFirst(firstChar, firstChar.toLowerCase());

		return name;
	}

	private static String getPackagePath(String packageName) {
		String packagePath = packageName.replace(".", "/");
		if (!packagePath.endsWith("/")) {
			packagePath = packagePath + "/";
		}

		return packagePath;
	}

	public static void saveService(GenerateInput input) {
		String path = input.getPath();
		String servicePkgName = input.getServicePkgName();
		String serviceName = input.getServiceName();
		String beanName = input.getBeanName();

		String text = getTemplate("service.txt", input.getCategory());
		text = text.replace("{date}", DateUtils.getDateTime());
		text = text.replace("{tableComment}", input.getTableComment());

		text = text.replace("{daoPackageName}", input.getDaoPackageName());
		text = text.replace("{beanPackageName}", input.getBeanPackageName());
		text = text.replace("{serviceName}", input.getServiceName());
		text = text.replace("{beanName}", beanName);
		text = text.replace("{beanParamName}", lowerFirstChar(beanName));

		text = text.replace("{servicePkgName}", servicePkgName);
		text = text.replace("{serviceName}", input.getServiceName());

		FileUtil.saveTextFile(text, path + File.separator + getPackagePath(servicePkgName)
				+ serviceName + ".java");
		log.debug("生成service：{}模板", serviceName);
	}

	public static void saveServiceImpl(GenerateInput input) {
		String path = input.getPath();
		String serviceImplPkgName = input.getServiceImplPkgName();
		String serviceImplName = input.getServiceImplName();
		String beanName = input.getBeanName();
		String daoName = input.getDaoName();

		String text = getTemplate("serviceImpl.txt", input.getCategory());
		text = text.replace("{date}", DateUtils.getDateTime());
		text = text.replace("{tableComment}", input.getTableComment());

		text = text.replace("{beanPackageName}", input.getBeanPackageName());
		text = text.replace("{daoPackageName}", input.getDaoPackageName());
		text = text.replace("{servicePkgName}", input.getServicePkgName());
		text = text.replace("{serviceImplPkgName}", serviceImplPkgName);

		text = text.replace("{beanName}", beanName);
		text = text.replace("{beanParamName}", lowerFirstChar(beanName));
		text = text.replace("{daoName}", daoName);
		text = text.replace("{daoParamName}", lowerFirstChar(daoName));
		text = text.replace("{serviceName}", input.getServiceName());
		text = text.replace("{serviceImplName}", serviceImplName);


		FileUtil.saveTextFile(text, path + File.separator + getPackagePath(serviceImplPkgName)
				+ serviceImplName + ".java");
		log.debug("生成serviceImpl：{}模板", serviceImplName);
	}

	public static void saveController(GenerateInput input) {
		String path = input.getPath();
		String beanPackageName = input.getBeanPackageName();
		String beanName = input.getBeanName();
		String servicePkgName = input.getServicePkgName();
		String serviceName = input.getServiceName();

		String text = getTemplate("controller.txt", input.getCategory());
		text = text.replace("{date}", DateUtils.getDateTime());
		text = text.replace("{tableComment}", input.getTableComment());
		text = text.replace("{servicePkgName}", servicePkgName);
		text = text.replace("{beanPackageName}", beanPackageName);
		text = text.replace("{serviceName}", serviceName);
		text = text.replace("{serviceParamName}", lowerFirstChar(serviceName));
		text = text.replace("{beanName}", beanName);
		text = text.replace("{beanParamName}", lowerFirstChar(beanName));
		text = text.replace("{controllerPkgName}", input.getControllerPkgName());
		text = text.replace("{controllerName}", input.getControllerName());

		FileUtil.saveTextFile(text,
				path + File.separator + getPackagePath(input.getControllerPkgName())
						+ input.getControllerName() + ".java");
		log.debug("生成controller：{}模板", input.getControllerName());
	}

	public static void saveHtmlList(GenerateInput input) {
		String path = input.getPath();

		String beanName = input.getBeanName();
		String beanParamName = lowerFirstChar(beanName);

		// 页面路径
		String htmlPkgName = "static"
				+ File.separator + "pages"
				+ File.separator + input.getModuleName()
				+ File.separator + StrUtil.lowerFirst(beanName);

		// 生成列表页面
		String text = getTemplate("htmlList.txt", input.getCategory());
		text = text.replace("{beanParamName}", beanParamName);
		text = text.replace("{beanName}", beanName);
		List<String> beanFieldNames = input.getBeanFieldName();
		List<String> beanFieldComments = input.getBeanFieldComment();
		text = text.replace("{columnsDatas}", getHtmlColumnsData(beanFieldNames, input.getCategory()));
		text = text.replace("{moduleName}", input.getModuleName());

		// ths表头从字段名换成备注名
		text = text.replace("{ths}", getHtmlThs(beanFieldComments));

		String listFileName = beanParamName + "List.html";
		FileUtil.saveTextFile(text,
				path + File.separator + htmlPkgName + File.separator + listFileName);
		log.debug("生成列表页面：{}模板", listFileName);

		// 生成添加页面
		text = getTemplate("htmlAdd.txt", input.getCategory());
		text = text.replace("{beanParamName}", beanParamName);
		text = text.replace("{addDivs}", getAddDivs(beanFieldNames, beanFieldComments));
		String addFileName = "add" + beanName + ".html";
		FileUtil.saveTextFile(text,
				path + File.separator + htmlPkgName + File.separator + addFileName);
		log.debug("生成添加页面：{}模板", addFileName);

		// 生成修改页面
		text = getTemplate("htmlUpdate.txt", input.getCategory());
		text = text.replace("{beanParamName}", beanParamName);
		text = text.replace("{addDivs}", getAddDivs(beanFieldNames, beanFieldComments));
		text = text.replace("{initData}", getInitData(beanFieldNames));
		String updateFileName = "update" + beanName + ".html";
		FileUtil.saveTextFile(text,
				path + File.separator + htmlPkgName + File.separator + updateFileName);
		log.debug("生成修改页面：{}模板", updateFileName);
	}

	private static CharSequence getInitData(List<String> beanFieldNames) {
		StringBuilder builder = new StringBuilder();
		beanFieldNames.forEach(b -> builder.append("\t\t\t\t\t\t\t$('#")
				.append(b)
				.append("').val(data.")
				.append(b)
				.append(");\n"));

		return builder.toString();
	}

	private static String getAddDivs(List<String> beanFieldNames, List<String> beanFieldComments) {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < beanFieldNames.size(); i++) {
			String beanFieldName = beanFieldNames.get(i);
			String beanFieldComment = beanFieldComments.get(i);
			if (!"id".equals(beanFieldName)
					&& !"createTime".equals(beanFieldName)
					&& !"updateTime".equals(beanFieldName)) {
				builder.append("\t\t\t<div class='form-group'>\n")
						.append("\t\t\t\t<label class='col-md-4 control-label'>")
						.append(beanFieldComment)
						.append("</label>\n")
						.append("\t\t\t\t<div class='col-md-8'>\n")
						.append("\t\t\t\t\t<input class='form-control' placeholder='")
						.append(beanFieldComment)
						.append("' type='text' name='")
						.append(beanFieldName)
						.append("' id='")
						.append(beanFieldName)
						.append("' data-bv-notempty='true' data-bv-notempty-message='")
						.append(beanFieldComment)
						.append(" 不能为空'>\n")
						.append("\t\t\t\t</div>\n")
						.append("\t\t\t</div>\n");
			}
		}
		return builder.toString();
	}

	private static String getHtmlThs(List<String> beanFieldComment) {
		StringBuilder builder = new StringBuilder();
		beanFieldComment.forEach(b -> builder.append("\t\t\t\t\t\t\t\t<th>{beanFieldComment}</th>\n"
				.replace("{beanFieldComment}", b)));
		return builder.toString();
	}

	private static String getHtmlColumnsData(List<String> beanFieldNames, Integer category) {
		StringBuilder builder = new StringBuilder();
		if (category == 0) {
			beanFieldNames.forEach(b ->
					builder.append("\t\t\t\t{\"data\" : \"")
							.append(b)
							.append("\", \"defaultContent\" : \"\"},\n"));
		} else {
			beanFieldNames.forEach(b ->
					builder.append("\t\t\t\t\t\ttr += '<td>' + d['")
							.append(b)
							.append("'] + '</td>'\n"));
		}

		return builder.toString();
	}

	private static String getHtmlColumnsData(List<String> beanFieldNames) {
		return getHtmlColumnsData(beanFieldNames, 0);
	}

}
